/*
实现异步日志缓冲区，用于存储日志信息，并提供日志写入接口。
通过空间复用，避免频繁申请内存，提高效率。
*/

#ifndef BUFFER_HPP
#define BUFFER_HPP

#include "util.hpp"
#include <iostream>
#include <vector>
#include <cassert>
#include <memory>

namespace xzt
{
    namespace log
    {
        const int max_buffer_size = 1 * 1024 * 1024;  // 缓冲区大小，单位：字节
        const int threshold_size = 8 * 1024 * 1024;  // 扩容阈值，单位：字节
        const int increment_size = 1 * 1024 * 1024;  // 线性扩容步长，单位：字节

        class Buffer
        {
        public:
            using ptr = std::shared_ptr<Buffer>;

            Buffer(int buffer_size = max_buffer_size): 
                _buffer(buffer_size), _read_idx(0), _write_idx(0) {}

            // 向缓冲区写入日志信息
            void push(const char* data, size_t len)
            {
                // 判断缓冲区是否已满，若已满：1）进行扩容；2）返回阻塞
                // 1)进行扩容
                _expand(len);
                // 2)返回阻塞
                // if(writeAbleSize() < len) { return; }

                // 向缓冲区写入日志信息
                std::copy(data, data + len, &_buffer[_write_idx]);
                // 更新写指针位置
                _moveWritePtr(len);
            }

            // 返回可写数据的长度 -- 该接口仅用于非扩容缓冲区模式
            size_t writeAbleSize() const
            {
                return _buffer.size() - _write_idx;
            }

            // 返回可读数据的起始地址
            const char* begin() const
            {
                return &_buffer[_read_idx];
            }
            // 返回可读数据的长度
            size_t readAbleSize() const
            {
                return _write_idx - _read_idx;
            }

            // 对读指针进行向后偏移
            void moveReadPtr(size_t len)
            {
                assert(len <= readAbleSize());
                _read_idx += len;
            }

            // 重置读写位置，清空缓冲区
            void reset()
            {
                _read_idx = 0;
                _write_idx = 0;
            }

            // 对buffer实现交换操作
            void swap(Buffer& rhs)
            {
                _buffer.swap(rhs._buffer);
                std::swap(_read_idx, rhs._read_idx);
                std::swap(_write_idx, rhs._write_idx);
            }

            // 判断缓冲区是否为空
            bool empty() const
            {
                return _read_idx == _write_idx;
            }
        private:
            // 会在push()函数中调用，向缓冲区写入日志信息时更新写指针位置
            void _moveWritePtr(size_t len)
            {
                assert(len <= _buffer.size() - _write_idx);
                _write_idx += len;
            }
            // 会在push()函数中调用，当缓冲区已满时，进行扩容操作
            void _expand(size_t len)
            {
                if(writeAbleSize() > len) { return; }

                // 需要扩容
                size_t new_size = 0;
                if(_buffer.size() < threshold_size)  // 缓冲区尺寸小于阈值，倍数扩容
                {
                    new_size = _buffer.size() * 2 + len;
                }
                else  // 缓冲区尺寸大于阈值，线性扩容
                {
                    new_size = _buffer.size() + increment_size + len;
                }
                
                _buffer.resize(new_size);
            }
        private:
            std::vector<char> _buffer;
            size_t _read_idx;  // 当前可读数据的指针
            size_t _write_idx;  // 当前可写数据的指针
        };
    }
}


#endif // BUFFER_HPP